package com.young.core.manager.impl;

import com.young.core.dao.LockDao;
import com.young.core.domain.LockDO;
import com.young.core.enums.LockTypeEnum;
import com.young.core.manager.LockManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class LockManagerImpl implements LockManager {

    @Autowired
    private LockDao lockDao;

    @Override
    public void ensure(String namespace) {
        LockDO lock = this.lockDao.get(namespace);
        if (lock == null) {
            this.lockDao.insert(namespace);
        }
    }

    /**
     *
     * @param namespace
     * @param owner
     * @param ttl
     * @return
     * 1、如果锁过期或锁不存在，此场景特别注意，当前节点是master时也可能存在锁意外丢失问题，比如DB在一个ttl内不可达
     *   1.1 抢锁成功，返回PROMOTED；
     *   1.2 抢锁失败，返回LEAVE
     * 2、如果锁已存在
     *   2.1 续约成功，返回STAY，表示master可以继续执行
     *   2.2 续约失败，返回LEAVE，表示master已丢失锁
     * 3、如果发生异常，表明锁状态不可预测，需要重试，则返回UNKNOWN
     */
    @Override
    public LockTypeEnum lock(String namespace, String owner, int ttl) {
        //检查锁是否过期
        LockDO lock = this.lockDao.get(namespace);
        //如果锁过期，则触发DB抢锁
        if (lock.isExpired(ttl)) {
            return this.lockDao.lock(namespace, owner, lock.getVersion()) ? LockTypeEnum.PROMOTED : LockTypeEnum.UNKNOWN;
        }

        //如果锁未过期，且持有者是自己，则续约
        if (owner.equals(lock.getOwner())) {
            return this.lockDao.keepAlive(namespace, owner, ttl) ? LockTypeEnum.STAY : LockTypeEnum.LEAVE;
        }
        return LockTypeEnum.UNKNOWN;
    }


    @Override
    public boolean unlock(String namespace, String owner) {
        return this.lockDao.unlock(namespace,owner);
    }
}
